/**
 * @(#)StretchIcon.java	1.0 03/27/12
 */
package com.hardson.toolkit.swing.image;

import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.image.ImageObserver;
import java.net.URL;

import javax.swing.ImageIcon;

/**
 * An <CODE>Icon</CODE> that scales its image to fill the component area,
 * excluding any border or insets, optionally maintaining the image's aspect
 * ratio by padding and centering the scaled image horizontally or vertically.
 * <P>
 * The class is a drop-in replacement for <CODE>ImageIcon</CODE>, except that
 * the no-argument constructor is not supported.
 * <P>
 * As the size of the Icon is determined by the size of the component in which
 * it is displayed, <CODE>StretchIcon</CODE> must only be used in conjunction
 * with a component and layout that does not depend on the size of the
 * component's Icon.
 *
 * @version 1.0 03/27/12
 * @author Darryl
 */
public class StretchIcon extends ImageIcon {

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * Determines whether the aspect ratio of the image is maintained.
	 * Set to <code>false</code> to allow th image to distort to fill the component.
	 */
	protected boolean proportionate = true;

	/**
	 * Creates a <CODE>StretchIcon</CODE> from an array of bytes.
	 *
	 * @param imageData an array of pixels in an image format supported by
	 *                  the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
	 *
	 * @see ImageIcon#ImageIcon(byte[])
	 */
	public StretchIcon(byte[] imageData) {
		super(imageData);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from an array of bytes with the specified
	 * behavior.
	 *
	 * @param imageData     an array of pixels in an image format supported by
	 *                      the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(byte[])
	 */
	public StretchIcon(byte[] imageData, boolean proportionate) {
		super(imageData);
		this.proportionate = proportionate;
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from an array of bytes.
	 *
	 * @param imageData   an array of pixels in an image format supported by
	 *                    the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
	 * @param description a brief textual description of the image
	 *
	 * @see ImageIcon#ImageIcon(byte[], java.lang.String)
	 */
	public StretchIcon(byte[] imageData, String description) {
		super(imageData, description);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from an array of bytes with the specified
	 * behavior.
	 *
	 * @see ImageIcon#ImageIcon(byte[])
	 * @param imageData     an array of pixels in an image format supported by
	 *                      the AWT Toolkit, such as GIF, JPEG, or (as of 1.3) PNG
	 * @param description   a brief textual description of the image
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(byte[], java.lang.String)
	 */
	public StretchIcon(byte[] imageData, String description, boolean proportionate) {
		super(imageData, description);
		this.proportionate = proportionate;
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the image.
	 *
	 * @param image the image
	 *
	 * @see ImageIcon#ImageIcon(java.awt.Image)
	 */
	public StretchIcon(Image image) {
		super(image);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the image with the specified
	 * behavior.
	 *
	 * @param image         the image
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(java.awt.Image)
	 */
	public StretchIcon(Image image, boolean proportionate) {
		super(image);
		this.proportionate = proportionate;
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the image.
	 *
	 * @param image       the image
	 * @param description a brief textual description of the image
	 *
	 * @see ImageIcon#ImageIcon(java.awt.Image, java.lang.String)
	 */
	public StretchIcon(Image image, String description) {
		super(image, description);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the image with the specified
	 * behavior.
	 *
	 * @param image         the image
	 * @param description   a brief textual description of the image
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(java.awt.Image, java.lang.String)
	 */
	public StretchIcon(Image image, String description, boolean proportionate) {
		super(image, description);
		this.proportionate = proportionate;
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified file.
	 *
	 * @param filename a String specifying a filename or path
	 *
	 * @see ImageIcon#ImageIcon(java.lang.String)
	 */
	public StretchIcon(String filename) {
		super(filename);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified file with the specified
	 * behavior.
	 *
	 * @param filename      a String specifying a filename or path
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(java.lang.String)
	 */
	public StretchIcon(String filename, boolean proportionate) {
		super(filename);
		this.proportionate = proportionate;
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified file.
	 *
	 * @param filename    a String specifying a filename or path
	 * @param description a brief textual description of the image
	 *
	 * @see ImageIcon#ImageIcon(java.lang.String, java.lang.String)
	 */
	public StretchIcon(String filename, String description) {
		super(filename, description);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified file with the specified
	 * behavior.
	 *
	 * @param filename      a String specifying a filename or path
	 * @param description   a brief textual description of the image
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(java.awt.Image, java.lang.String)
	 */
	public StretchIcon(String filename, String description, boolean proportionate) {
		super(filename, description);
		this.proportionate = proportionate;
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified URL.
	 *
	 * @param location the URL for the image
	 *
	 * @see ImageIcon#ImageIcon(java.net.URL)
	 */
	public StretchIcon(URL location) {
		super(location);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified URL with the specified
	 * behavior.
	 *
	 * @param location      the URL for the image
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(java.net.URL)
	 */
	public StretchIcon(URL location, boolean proportionate) {
		super(location);
		this.proportionate = proportionate;
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified URL.
	 *
	 * @param location    the URL for the image
	 * @param description a brief textual description of the image
	 *
	 * @see ImageIcon#ImageIcon(java.net.URL, java.lang.String)
	 */
	public StretchIcon(URL location, String description) {
		super(location, description);
	}

	/**
	 * Creates a <CODE>StretchIcon</CODE> from the specified URL with the specified
	 * behavior.
	 *
	 * @param location      the URL for the image
	 * @param description   a brief textual description of the image
	 * @param proportionate <code>true</code> to retain the image's aspect ratio,
	 *                      <code>false</code> to allow distortion of the image to
	 *                      fill the
	 *                      component.
	 *
	 * @see ImageIcon#ImageIcon(java.net.URL, java.lang.String)
	 */
	public StretchIcon(URL location, String description, boolean proportionate) {
		super(location, description);
		this.proportionate = proportionate;
	}

	/**
	 * Paints the icon. The image is reduced or magnified to fit the component to
	 * which
	 * it is painted.
	 * <P>
	 * If the proportion has not been specified, or has been specified as
	 * <code>true</code>,
	 * the aspect ratio of the image will be preserved by padding and centering the
	 * image
	 * horizontally or vertically. Otherwise the image may be distorted to fill the
	 * component it is painted to.
	 * <P>
	 * If this icon has no image observer,this method uses the <code>c</code>
	 * component
	 * as the observer.
	 *
	 * @param c the component to which the Icon is painted. This is used as the
	 *          observer if this icon has no image observer
	 * @param g the graphics context
	 * @param x not used.
	 * @param y not used.
	 *
	 * @see ImageIcon#paintIcon(java.awt.Component, java.awt.Graphics, int, int)
	 */
	@Override
	public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
		Image image = this.getImage();
		if (image == null) {
			return;
		}
		Insets insets = ((Container) c).getInsets();
		x = insets.left;
		y = insets.top;

		int w = c.getWidth() - x - insets.right;
		int h = c.getHeight() - y - insets.bottom;

		if (this.proportionate) {
			int iw = image.getWidth(c);
			int ih = image.getHeight(c);

			if (iw * h < ih * w) {
				iw = (h * iw) / ih;
				x += (w - iw) / 2;
				w = iw;
			} else {
				ih = (w * ih) / iw;
				y += (h - ih) / 2;
				h = ih;
			}
		}

		ImageObserver io = this.getImageObserver();
		g.drawImage(image, x, y, w, h, io == null ? c : io);
	}

	/**
	 * Overridden to return 0. The size of this Icon is determined by
	 * the size of the component.
	 *
	 * @return 0
	 */
	@Override
	public int getIconWidth() {
		return 0;
	}

	/**
	 * Overridden to return 0. The size of this Icon is determined by
	 * the size of the component.
	 *
	 * @return 0
	 */
	@Override
	public int getIconHeight() {
		return 0;
	}
}
